package com.tcm.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.tcm.entity.User;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于Jwt的权限验证工具类
 * @author Guqier
 * @version 1.0
 * @date 2023/7/1 11:24
 */
public class AccessTokenUtil {

    /**
     * 密钥
     */
    private static final String SECRET_KEY = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    /**
     * 持续时间，即有效期
     */
    public final static long KEEP_TIME = 24 * 60 * 60 * 1000;

    /**
     * 从request对象中获取token
     * @param request http请求对象
     * @return AccessToken
     */
    public static String getAccessToken(HttpServletRequest request){
        return request.getHeader("token");
    }

    /**
     * 配置AccessToken到响应头
     * @param response http响应体
     */
    public static void setAccessToken(HttpServletResponse response, String accessToken){
        response.setHeader("token", accessToken);
    }

    /**
     * 从request对象中获取用户ID
     * @param request http请求对象
     * @return 用户ID
     */
    public static Long getUserId(HttpServletRequest request){
        String accessToken = getAccessToken(request);
        return getUserId(accessToken);
    }

    /**
     * 从request对象中获取用户账号
     * @param request http请求对象
     * @return 用户账号
     */
    public static String getUserAccount(HttpServletRequest request){
        String accessToken = getAccessToken(request);
        return getUserAccount(accessToken);
    }


    /**
     * 通过AccessToken获取用户ID
     * @param accessToken AccessToken
     * @return 用户ID
     */
    public static Long getUserId(String accessToken){
        Map<String, String> jwtTokenPayloadMap = getJwtTokenPayloadMap(accessToken);
        return Long.parseLong(jwtTokenPayloadMap.get("id"));
    }

    /**
     * 通过AccessToken获取用户账号
     * @param accessToken AccessToken
     * @return 用户账号
     */
    public static String getUserAccount(String accessToken){
        Map<String, String> jwtTokenPayloadMap = getJwtTokenPayloadMap(accessToken);
        return jwtTokenPayloadMap.get("account");
    }

    /**
     * 生成AccessToken
     * @param id 用户ID
     * @param account 账号
     * @return 生成的AccessToken
     */
    public static String generateAccessToken(Long id, String account){
        HashMap<String, String> map = new HashMap<>();
        map.put("id", String.valueOf(id));
        map.put("account", account);
        return generateJwtToken(map);
    }

    /**
     * 生成AccessToken
     * @param user 用户对象
     * @return 生成的AccessToken
     */
    public static String  generateAccessToken(User user){
        return generateAccessToken(user.getId(), user.getAccount());
    }

    /**
     * 验证AccessToken
     * @param accessToken AccessToken字符串
     * @return true为验证通过，false为验证失败
     */
    public static boolean verifyAccessToken(String accessToken){
        try {
            verifyJwtToken(accessToken);//调用token解析的工具类进行解析
            return true;  // 验证通过
        } catch (Exception e) {
            // 验证错误，返回错误信息
            return false;
        }
    }

    /**
     * 验证AccessToken
     * @param request http请求对象
     * @return true为验证通过，false为验证失败
     */
    public static boolean verifyAccessToken(HttpServletRequest request){
        String accessToken = getAccessToken(request);
        return verifyAccessToken(accessToken);
    }

    /**
     * 生成token
     * @param map payload中需要放置的信息
     * @return 返回生成的token
     */
    private static String generateJwtToken(Map<String, String> map) {
        // 获取JWT构造对象
        JWTCreator.Builder builder = JWT.create();
        // 存入数据到payload
        map.forEach((k, v) -> {
            builder.withClaim(k, v);
        });
        String token = builder.withExpiresAt(new Date(System.currentTimeMillis() + KEEP_TIME)) // token有效期
                .sign(Algorithm.HMAC256(SECRET_KEY)); // 签名

        return token;
    }

    /**
     * 验证token DecodedJWT 为解密之后的对象 可以获取payload中添加的数据
     * @param token token字符串
     * @return DecodedJWT为解密之后的对象，可以获取payload中添加的数据
     */
    private static DecodedJWT verifyJwtToken(String token) {
        return JWT.require(Algorithm.HMAC256(SECRET_KEY)).build().verify(token);
    }

    /**
     * 获取token中payload中的添加的参数
     * @param token token字符串
     * @return 结果map集合
     */
    private static Map<String, String> getJwtTokenPayloadMap(String token) {
        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build().verify(token);
        Map<String, String> payload = new HashMap<>();

        //Map<String, Claim> claims = verify.getClaims(); //获取payload中所有的参数
        //verify.getClaim("userName").asString();  //通过key获取value,转成对应的类型

        Map<String, Claim> claims = verify.getClaims();
        claims.forEach((k, v) -> {
            payload.put(k, v.asString());
        });

        return payload;
    }

}
